﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Linq;
using System.Text;
//for serialization
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

using Model.Items;
using Model.Events;
using Model.Items.Weapons;
using Model.Items.Weapons.Parts;
using Model.Raw_Materials;
using Model.Crafters;
using Model.Hero;

namespace Model
{
    class runner
    {
        [STAThread]
        static void Main(string[] args)
        {
            Console.WriteLine("Game running");

            Blacksmith blacksmith = new Blacksmith { Name = "Thor Thorstein", AvailableSkillPoints = 0, Race = "Dwarf", Profession = "Blacksmith", Level = 5, Intellect = 16, XP = 0 };
            blacksmith.Skills.Add(new Skill { Name = "Craftmanship", SkillType = Skill.SkillTypes.Craftmanship, SkillPoints = 27 });
            blacksmith.Skills.Add(new Skill { Name = "Flair", SkillType = Skill.SkillTypes.Flair, SkillPoints = 23 });

            Console.WriteLine("\n" + blacksmith + "\n");

            Ore MithrilOre = new Ore("Mithril", 80, 6, 200);
            Metal MithrilBar = new Metal(MithrilOre);

            Ore CopperOre = new Ore("Copper", 32, 4, 26);
            Metal CopperBar = new Metal(CopperOre);

            Console.WriteLine("\n" + MithrilOre + "\n\n\n" + MithrilBar + "\n");

            Ornament ornament = new Ornament { Value = 60 };


            /*
            blacksmith.XP += 1800;
            Console.WriteLine("\n" + blacksmith + "\n");

            blacksmith.XP += 3000;
            Console.WriteLine("\n" + blacksmith + "\n");*/

            SwordBlade blade = new SwordBlade(blacksmith, MithrilBar, ornament);
            Console.WriteLine("\n" + blade + "\n");
            SwordHilt hilt = new SwordHilt(blacksmith, CopperBar, ornament);
            Console.WriteLine("\n" + hilt + "\n");
            Sword sword = new Sword(blade, hilt);
            Console.WriteLine("\n" + sword + "\n");

            Sword swordcopy = null;
            try
            {
                swordcopy = CloneObject(sword);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.InnerException.Message);
            }

            swordcopy.crafter = sword.crafter;
            //Console.WriteLine("swordblade: " + swordcopy.swordBlade);
            Console.WriteLine("copy of sword: " + swordcopy);

            /* lav copy method i alle class'er
             * gør serialization færdig i crafter
             * hvad sker der når en item er færdig? - afkobl crafter + kopier skills (fastfryser skillpoints)
             * hvad sker der når en crafters skill går op imens han laver en item?
             * 
             * */


            

            Boolean boo = false; ///!!!!!!!!!!!!!!!!
            sword.ManHours = 6;
            while (boo)
            {
                if (sword.Progress >= 100)
                    boo = false;
                //simulate progress
                Console.Clear();
                Console.WriteLine("ManHours = " + sword.ManHours);
                Console.WriteLine("Progress on sword: " + string.Format("{0:#,###0.00}%", sword.Progress));
                Console.WriteLine("Hours left = " + (int)((double)sword.ManHours - sword.ManHoursDone));
                sword.ManHoursDone += 1.0 / 12.0;
                Thread.Sleep(50);

            }

            /*
            Console.WriteLine("Creating hero...");
            Race race_orc = new Race { Name = "Orc", Agility = 7, Intellect = 4, Perception = 6, Strength = 10, Vitality = 9 };
            Hero.Hero hero = new Hero.Hero("Grom Hellscream", race_orc);
            hero.AwardXP(35600);
            sword.Attack_Rating = 45;
            //giving the sword some defense to represent armor
            sword.Defense_Rating = 60;
            hero.EquipItem(sword);
            //dual wielding:
            //hero.EuipItemInSlot(sword, hero.ragDoll.Weapon_Left);

            Feat First_Strike = new Feat("First Strike", 5);
            First_Strike.First_Strike = 5;
            hero.AddFeat(First_Strike);
            Console.WriteLine(hero);

            
            Adventure.Dungeon dungeon = new Model.Adventure.Dungeon("Temple of elemental evil");
            Adventure.Encounter encounter = new Model.Adventure.Encounter();
            dungeon.AddEncounter(encounter);

            //create a lvl # orc
            Model.Adventure.Monters.Orc mob = new Model.Adventure.Monters.Orc(race_orc, 7);
            mob.Name = "Orc grunt";
            for (int i = 1; i < 6; i++)
            {
                Feat Riposte = new Feat(("Riposte " + i), 5);
                Riposte.Riposte = i;
                mob.AddFeat(Riposte);
            }
            
            Feat Riposte1 = new Feat("Riposte IV", 4);
            Riposte1.Riposte = 1;
            mob.AddFeat(Riposte1);
            /*Feat Riposte2 = new Feat("Riposte II", 5);
            Riposte2.Riposte = 2;
            mob.AddFeat(Riposte2);
     
            //Console.WriteLine(mob);
            encounter.AddMonster(mob);

            //List<Character> monsters = new List<Character>();
            //monsters.Add(mob);
            //Console.WriteLine("pitching " + mob.Name + " against hero!");
            //int round = 1;
            //List<Model.Adventure.NPC> mobs = new List<Model.Adventure.NPC>();
            //mobs.Add(mob);
            //add some low lvl peons
            for (int i = 0; i < 4; i++)
            {
                Model.Adventure.Monters.Orc peon = new Model.Adventure.Monters.Orc(race_orc, 1);
                peon.Name = "Orc peon";
                Console.WriteLine(peon);
                encounter.AddMonster(peon);               
            }
            Console.WriteLine(dungeon);

            List<Character> heroes = new List<Character>();
            heroes.Add(hero);
            //add another hero to party
            Hero.Hero hero2 = new Hero.Hero("Gurk Longlegs", race_orc);
            hero2.AwardXP(20000);            
            hero2.EquipItem(sword);
            //dual wielding:
            hero2.EuipItemInSlot(sword, hero.ragDoll.Weapon_Left);
            heroes.Add(hero2);

            //Thread thread = new Thread(dungeon.EnterDungeon);            
            //thread.Start(heroes);            

            /*
            int workerThreads;
            int portThreads;
            ThreadPool.GetMaxThreads(out workerThreads, out portThreads);
            Console.WriteLine("\nMaximum worker threads: \t{0}" +
                "\nMaximum completion port threads: {1}",
                workerThreads, portThreads);
            //*/
            /*
            ThreadPool.QueueUserWorkItem(new WaitCallback(dungeon.EnterDungeon), heroes);
            
                        
            //should be done in client when time comes
            bool go = true;
            W : while (go)
            {                
                foreach (Character _hero in heroes)
                {
                    //Console.WriteLine("Checking primary target");
                    if (_hero.PrimaryTarget == null || _hero.PrimaryTarget.CurrentHealth == 0)
                    {                        
                        //Console.WriteLine("Client picking primary target");     

                        //choose new target - simulating waiting for client to pick a target
                        Character monster = null;
                        while (monster == null)
                        {
                            monster = (Character)dungeon.GetRandomMonster();                      
                            Thread.Sleep(50);
                            //timeout!!!!
                            if (dungeon.Cleared)
                            {
                                go = false;
                                goto W;
                            }
                        }
                        //----

                        //Console.WriteLine("new primary target = {0}", monster.Name);
                        _hero.PrimaryTarget = monster;
                        Console.WriteLine("{0}'s new target is {1} (health) {2}", _hero.Name, monster.Name, monster.CurrentHealth); 
                        dungeon.MRE.Set();
                        //Console.WriteLine("Signaled!");                                                                     
                    }
                }
                //break when dungeon is cleared
                if (dungeon.Cleared)
                    break;
            }//*/

            
            /*
            //list of the deads for later awarding XP and loot
            //List<Model.Adventure.NPC> deads = new List<Model.Adventure.NPC>();
            bool go = true;
            Combat : while (go)
            {                
                Console.WriteLine("Round #" + round++);
                Adventure.Combat.RoundOfCombat(hero, mobs, mob);               
                //primary mob died. get new one
                if (mob.CurrentHealth <= 0)
                {
                    foreach (Model.Adventure.NPC _mob in mobs)
                    {
                        //only get the alive ones
                        if (_mob.CurrentHealth > 0)
                        {                          
                            //assign new primary mob
                            mob = _mob as Model.Adventure.Monters.Orc;                            
                            break;
                        }
                    }
                    //look for live monster
                    
                    foreach (Model.Adventure.NPC _mob in mobs)
                    {
                        //alive monster found. continue combat and stop searching
                        if (_mob.CurrentHealth > 0)
                        {
                            //continue Combat;
                            goto Combat;
                            //go = true;
                            //break;
                        }
                    } //end foreach    
                    //no alive monsters found. stop combat
                    break;
                }                                                
            }//end while
            if(hero.CurrentHealth > 0)
                Console.WriteLine(hero.Name + " survived the fight with " + hero.CurrentHealth + " health left");
            long XP = 0;
            foreach (Model.Adventure.NPC _mob in mobs)
                XP += _mob.XP_Value;
            hero.AwardXP(XP);
            Console.WriteLine("{0} was awarded {1} XP", hero.Name, XP);
                
            
            Adventure.Monters.Orc monster = new Model.Adventure.Monters.Orc { Level = 1 };
            for (int i = 1; i < 100; i++)
            {
                monster.Level = i;
                //Console.WriteLine("Max loot value for lvl " + i + " monster: " + monster.MaxLootValue());                
            }

            hero.Level = 1;
            for (int i = 1; i < 100; i++)
            {                
                Console.WriteLine("XP to reach lvl " + i + ": " + (hero.XPToLvl - hero.XP));
                hero.AwardXP(hero.XPToLvl);
            }
            //*/
            
            

            //Console.WriteLine("\n" + MithrilBar + "\n");
            //GameDate.Test();

            /*System.Windows.Controls.TextBlock block = new System.Windows.Controls.TextBlock { TextWrapping = System.Windows.TextWrapping.Wrap };

            //GameDate date = new GameDate(2008, 8, 31, 21, 14);
            Event e = new Event(new GameDate(2008, 8, 31, 21, 14), Event.EventTypes.Random_Event, "Købte 60 Heste på marked", "Heste");
            //e.KeyWord = "Heste";
            //e.EventDescription = "Købte 60 Heste på marked";
            Console.WriteLine(e);
            LogEntry entry = new LogEntry(e);
            List<System.Windows.Documents.Hyperlink> link = entry.LogFormat(block);
            link[1].Click += delegate { System.Windows.MessageBox.Show("clicky link!"); };
            
            System.Windows.Window win = new System.Windows.Window { Content = block };
            win.ShowDialog();
            //*/


            
            Spells.Spellbook spellbook = new Model.Spells.Spellbook(5);
            Spells.Spell fireball_4 = new Model.Spells.Spell("Fireball", 0, 0, 0, null, null, null, 0, 0);
            if (spellbook.Add_Spell(fireball_4) == false)
                Console.WriteLine("Unable to add spell:\n{0}", fireball_4);
            Spells.Spell fireball_5 = new Model.Spells.Spell("Fireball", 0, 0, 0, null, null, null, 0, 0);
            spellbook.Remove_Spell(fireball_5);
            if (spellbook.Add_Spell(fireball_5) == false)
                Console.WriteLine("Unable to add spell:\n{0}", fireball_5);
            Console.WriteLine(spellbook);

            Herb herb = new Herb();
            //herb.GenerateRandomHerbNames(15);
            Console.WriteLine("End of main");
            Console.Read();
        }//*/

        public static T CloneObject<T>(T obj) where T : class, ISerializable
        {

            MemoryStream memoryStream = new MemoryStream();

            BinaryFormatter serializer = new BinaryFormatter();

            serializer.Serialize(memoryStream, obj);

            memoryStream.Seek(0, SeekOrigin.Begin);
            
            return serializer.Deserialize(memoryStream) as T;
           
        }
    }
}
